package org.mte.swift.builder;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.mte.sakn.file.FileObject;
import org.mte.sakn.file.FileSystem;
import org.mte.sakn.properties.PropertiesHandler;
import org.mte.swift.builder.handler.ModelHandler;
import org.mte.swift.builder.model.SwiftModel;
import org.mte.swift.builder.model.app.AppModel;
import org.mte.swift.builder.model.template.Template;
import org.mte.swift.builder.template.TemplateProcessor;


public class SwiftBuilderImpl implements SwiftBuilder {
	
	private static final String[] JAVA_FILE_TYPES = {".java"};
	private static final String[] VIEW_FILE_TYPES = {".jspx", ".properties", ".xml"};
	
	private static final String WORK_ROOT_KEY = "target.workRoot";
	private static final String SOURCE_PATH_KEY = "target.sourcePath";
	private static final String WEB_PATH_KEY = "target.webPath";
	private static final String PACKAGE_KEY = "target.package";
	private static final String WEB_DIR_KEY = "target.webDir";
	private static final String ENTITY_PATH_KEY = "source.entityPath";
	private static final String BASE_ENTITY_CLASS_NAME_KEY = "source.entityClassName";
	
	protected SwiftModel swiftModel = null;
	
	protected PropertiesHandler propertiesHandler = null;
	
	protected FileSystem fileSystem = null;
	
	protected TemplateProcessor templateProcessor = null;
	
	protected ModelHandler modelHandler = null;
			
	public SwiftBuilderImpl() {
	}
		
	public PropertiesHandler getPropertiesHandler() {
		return propertiesHandler;
	}

	public void setPropertiesHandler(PropertiesHandler propertiesHandler) {
		this.propertiesHandler = propertiesHandler;
	}

	public TemplateProcessor getTemplateProcessor() {
		return templateProcessor;
	}

	public void setTemplateProcessor(TemplateProcessor templateProcessor) {
		this.templateProcessor = templateProcessor;
	}

	public FileSystem getFileSystem() {
		return fileSystem;
	}

	public void setFileSystem(FileSystem fileSystem) {
		this.fileSystem = fileSystem;
	}
	
	public ModelHandler getModelHandler() {
		return modelHandler;
	}

	public void setModelHandler(ModelHandler modelHandler) {
		this.modelHandler = modelHandler;
	}

	public void build() throws Exception {
	
	 /* init SwiftModel with input parameters */
		initSwiftModel();
		
	 /* read Entity.java with reflection and fills SwiftModel */
		modelHandler.fillEntity(swiftModel);
	
	 /* build webStructures */
		modelHandler.initStructures(swiftModel);
		
	 /* fills placeholders */
		modelHandler.fillPlaceholders(swiftModel);
		
	 /* retrieve TemplateFiles */
		retrieveSourceTemplates();
		retrieveWebTemplates();
		
	 /* replace placeholder for each template */
		templateProcessor.processTemplates(swiftModel);
		
	 /* saves templates processed */   
		saveTemplates();
		
	 /* copy Entity.java in target package.domain */
	   //copyEntities();
	    
	   System.out.println(swiftModel.toString());
	}
		
	private void initSwiftModel() {
		swiftModel = new SwiftModel();
		swiftModel.setTargetPackage(propertiesHandler.getString(PACKAGE_KEY));
		String workRoot = propertiesHandler.getString(WORK_ROOT_KEY);
		swiftModel.setSourcePath(workRoot, propertiesHandler.getString(SOURCE_PATH_KEY));
		swiftModel.setWebPath(workRoot, propertiesHandler.getString(WEB_PATH_KEY));
		swiftModel.setEntityPath(workRoot, propertiesHandler.getString(ENTITY_PATH_KEY));
		
		List<String> webDirs = propertiesHandler.getList(WEB_DIR_KEY); 
		List<String> targetPackages = propertiesHandler.getList(PACKAGE_KEY); 
		swiftModel.setAppModels(propertiesHandler.getList(BASE_ENTITY_CLASS_NAME_KEY));
		int i = 0;
		for (AppModel appModel : swiftModel.getAppModels()) {
			String webDir = webDirs.get(i);
			String targetPackage = targetPackages.get(i);
			appModel.setWebDir(webDir);
			appModel.setTargetPackage(swiftModel.getTargetPackage(), targetPackage);
			appModel.setWebPath(swiftModel.getWebPath(), webDir);
			i++;
		}
		
	}
	
	private void retrieveSourceTemplates() throws IOException {
		 List<FileObject> files = retrieveFiles(fileSystem, JAVA_FILE_TYPES);
		 for (FileObject fo : files) {
			 fo.loadContent();			 
			 String parent = fo.getParent();
			 int posParent = parent.indexOf("java");
			 parent = parent.substring(posParent + 5);
			 parent = parent.replaceAll("\\\\", "/");
			 int pos = fo.getName().lastIndexOf(".");
			 String path = parent + "/" + fo.getName().substring(0, pos);
			 swiftModel.addSourceTemplate(path, fo.getContentToString());
		 }
	}
	
	private void retrieveWebTemplates() throws IOException {
		 List<FileObject> files = retrieveFiles(fileSystem, VIEW_FILE_TYPES);
		 for (FileObject fo : files) {
			 fo.loadContent();
			 int pos = fo.getName().lastIndexOf(".");
			 String path = fo.getName().substring(0, pos);
			 //for (AppModel appModel : swiftModel.getAppModels()) {
			 swiftModel.addWebTemplate(path, fo.getContentToString());
			 //}
		 }
	}
	
	private List<FileObject> retrieveFiles(FileSystem fileSystem, String[] types) {
		List<FileObject> files = new ArrayList<FileObject>();
		roolFiles(fileSystem, files, types);
		return files;
	}
	
	private void roolFiles(FileSystem fileSystem, List<FileObject> files, String[] types) {
		if (fileSystem.getDirs() != null) {
			for (FileSystem dir : fileSystem.getDirs()) {
				if (dir.getFiles() != null) {
					for (FileObject fo : dir.getFiles()) {
						for (String type : types) {
							if (fo.getName().indexOf(type) != -1) {
								files.add(fo);
							}
						}
					}					
				}				
				roolFiles(dir, files, types);				
			}
		}
	}
	
	private void saveTemplates() throws IOException {
		for (AppModel appModel : swiftModel.getAppModels()) {
			for (Template template : appModel.getTemplateSet().getEntities()) {
				FileObject fo = fileSystem.createFileObject(template.getPath());
				fo.setContent(template.getContent());
				String parent = fo.getParent();
				(new File(parent)).mkdirs();				
				fo.write();
			}
			
		}
	}
	
	private void copyEntities() throws IOException {
		for (AppModel appModel : swiftModel.getAppModels()) {
			String entityFileName =  appModel.getEntity().getName() + ".java";
			String pathFrom = swiftModel.getEntityPath() + entityFileName;
			String pathTo = swiftModel.getSourcePath() + "domain/" + entityFileName;
			System.out.println("pathFrom=" + pathFrom);
			System.out.println("pathTo=" + pathTo);
			FileObject fileObject = fileSystem.createFileObject(pathFrom);
			fileObject.loadContent();
			String content = fileObject.getContentToString();
			content = content.replaceAll("\\b[package]+\\s[a-z\\.]+[\\;]", "package " +  swiftModel.getTargetPackage() + ".domain;");
			fileObject.setContent(content);
			fileObject.write(pathTo);
		}		
	}
	
	/**/
	
/*	public void build1() throws Exception {
		System.out.println("propertiesHandler=" + propertiesHandler);

		//recupera dati entità
		
		//lettura files di skeleton
		List<FileObject> javaFiles = retrieveFiles(fileSystem, JAVA_FILE_TYPES);
		List<FileObject> viewFiles = retrieveFiles(fileSystem, VIEW_FILE_TYPES);
		
		//sostituzione segnaposti nello skeleton
		replaceFiles(javaFiles);
		replaceFiles(viewFiles);
		
		//salvataggio files
		//TODO targetJavaRoot sul properties devono essere relative al root del progetto, 
		//quindi il percorso assoluto deve essere calcolato
		saveFiles(javaFiles, propertiesHandler.getString("targetJavaRoot"), JAVA_SKELETON_SUB_DIR);
		saveFiles(viewFiles, propertiesHandler.getString("targetWebRoot"), VIEW_SKELETON_SUB_DIR);
	}*/
	

	
/*	private void replaceFiles(List<FileObject> files) throws Exception {
		if (files != null) {
			for (FileObject fo : files) {
				fo.loadContent();
				String content = fo.getContentToString();
				content = templateProcessor.processTemplate(content);
				fo.setContent(content);
			}
		}			
	}*/
	
/*	private void saveFiles(List<FileObject> files, String path, String subDir) throws Exception {
		if (files != null) {
			String skeletonPath = fileSystem.getRoot().getPath() + "/" + subDir;
			System.out.println("skeletonPath=" + skeletonPath);
			for (FileObject fo : files) {
				String filePath = fo.getPath();
				System.out.println("filePath1=" + filePath);
				filePath = filePath.substring(skeletonPath.length());
				System.out.println("filePath2=" + filePath);
				filePath = templateProcessor.retrieveTemplateName(filePath);
				filePath = filePath.substring(0, filePath.lastIndexOf("."));
				System.out.println("filePath3=" + filePath);
				filePath = path + filePath;		
				System.out.println("filePath4=" + filePath);
				//System.out.println(fo.getPath() + "-->" + filePath);
				File nfo = new File(filePath);
				(new File(nfo.getParent())).mkdirs();
				//System.out.println("parent=" + nfo.getParent() + "-" + nfo.getName());
				fo.write(filePath);
			}
		}
	}*/
	 

}
